﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace NetworkData.Spider
{
    /// <summary>
    /// This is a very simple object that
    /// allows the spider to determine when
    /// it is done. This object implements
    /// a simple lock that the spider class
    /// can wait on to determine completion.
    /// Done is defined as the spider having
    /// no more work to complete.
    /// 
    /// This spider is copyright 2003 by Jeff Heaton. However, it is
    /// released under a Limited GNU Public License (LGPL). You may 
    /// use it freely in your own programs. For the latest version visit
    /// http://www.jeffheaton.com.
    ///
    /// </summary>
    public class Done
    {

        /// <summary>
        /// The number of SpiderWorker object
        /// threads that are currently working
        /// on something.
        /// </summary>
        private int _mActiveThreads;

        /// <summary>
        /// This boolean keeps track of if
        /// the very first thread has started
        /// or not. This prevents this object
        /// from falsely reporting that the spider
        /// is done, just because the first thread
        /// has not yet started.
        /// </summary>
        private bool _mStarted;



        /// <summary>
        /// This method can be called to block
        /// the current thread until the spider
        /// is done.
        /// </summary>
        public void WaitDone()
        {
            Monitor.Enter(this);
            while (_mActiveThreads > 0)
            {
                Monitor.Wait(this);
            }
            Monitor.Exit(this);
        }

        /// <summary>
        /// Called to wait for the first thread to
        /// start. Once this method returns the
        /// spidering process has begun.
        /// </summary>
        public void WaitBegin()
        {
            Monitor.Enter(this);
            while (!_mStarted)
            {
                Monitor.Wait(this);
            }
            Monitor.Exit(this);
        }


        /// <summary>
        /// Called by a SpiderWorker object
        /// to indicate that it has begun
        /// working on a workload.
        /// </summary>
        public void WorkerBegin()
        {
            Monitor.Enter(this);
            _mActiveThreads++;
            _mStarted = true;
            Monitor.Pulse(this);
            Monitor.Exit(this);
        }

        /// <summary>
        /// Called by a SpiderWorker object to
        /// indicate that it has completed a
        /// workload.
        /// </summary>
        public void WorkerEnd()
        {
            Monitor.Enter(this);
            _mActiveThreads--;
            Monitor.Pulse(this);
            Monitor.Exit(this);
        }

        /// <summary>
        /// Called to reset this object to
        /// its initial state.
        /// </summary>
        public void Reset()
        {
            Monitor.Enter(this);
            _mActiveThreads = 0;
            Monitor.Exit(this);
        }
    }
}
